/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.foment.gem;
import config.*;
import java.io.*;
import java.net.*;
import java.sql.*;
import java.util.HashSet;
import javax.sql.rowset.CachedRowSet;
import org.foment.data.*;
//import org.foment.dialogs.*;

/**
 *
 * klasa ClientHandler, nit koja obavlja u petlji komunikaciju sa 
 * serverom
 * @author dusan
 */
public class Client extends Thread
{
    public Client() {

        // uspostavljamo vezu sa serverom i otvaramo stream-ove
        try {

            server = new Socket(TransferProtocol.HOST, TransferProtocol.PORT);
            out    = new ObjectOutputStream(server.getOutputStream());
            in     = new ObjectInputStream(server.getInputStream());

            //start();
        }
        catch (IOException e) {System.out.println("Client: " +e.getMessage());}
        System.out.println("Client: connection established and streams opened successfully");
    }
   
    @Override
    public void run() {

        // saljemo upit serveru i vracamo rezultat nazad
        // potom ga ispisujemo
        try {
            /*
            send(TransferProtocol.SQL_QUERY, new String("SELECT EmployeeFirstName, EmployeeSurname, EmployeeID, EmployeeJMBG from Employee"));
            System.out.println("Client: command SQL_QUERY sent");
            
            // potom primamo rezultat...
            command = in.readShort();
             // ako je rezultat podatak...
            if (command == TransferProtocol.SQL_DATA)
            {
                SqlData data = (SqlData)in.readObject();
                System.out.println("Client: data recieved! Printing...");
                data.print();
            }

            */

            while(true) {

                // receives message from server and notifies all other listeners
                receive();
            }

        }
        catch (IOException e) {
            System.err.print("Client, run: " + e.getMessage());
            reconnect();
        }
        catch (ClassNotFoundException e) {System.err.println("Client, run: " + e.getMessage());}
    }

    
    private void reconnect() {

       try {

            if (server != null)
                server.close();

            if (in != null)
                in.close();

            if (out != null)
                out.close();

            server = new Socket(TransferProtocol.HOST, TransferProtocol.PORT);
            out    = new ObjectOutputStream(server.getOutputStream());
            in     = new ObjectInputStream(server.getInputStream());

            //start();
        }
        catch (IOException e) {System.out.println("Client: " +e.getMessage());}
        System.out.println("Client: connection established and streams opened successfully");

    }

    @Override
    protected void finalize() throws Throwable {
        
        try {

            in.close();
            out.close();
            server.close();
            System.out.println("Client.finalize(): streams closed!");
        }
        catch(IOException e) {System.err.println("Client.finalize() " + e.getMessage());}
        super.finalize();
    }
    
    
    public void send(short command, Object message) {
        try {

            out.writeShort(command);
            out.flush();
            out.writeObject(message);
            out.flush();
        }
        catch(IOException e) {
           
            System.err.println("Client.send() " + e.getMessage());
        }
    }

    /* receives message from the server
       - first receives short command, to determine what kind of message it is
     * - than it receives message (object) itself
     */
    public void receive() throws IOException, ClassNotFoundException {
       command = in.readShort();
       message = in.readObject();

       // notify all listeners, that message is received, and send them the message
       notifyMessageReceived(command, message);
    }


    public int getCommand() {
        return command;
    }

    public Object getMessage() {

        return message;
    }


  /**
   * Registers a listener with a client
   * @return true if added. false if the specified listener is already listening
   * for the events of the specified client
   * @param clientListener Listener object
  */
  public boolean addListener(ClientListener clientListener) {
    if (_clientListeners.contains(clientListener)) return false;
    _clientListeners.add(clientListener);
    return true;
  }

  /**
   * Removes a listener from the client
   * @return true if success. false if the specified listener was not listening
   * to the specified client
   * @param clientListener The listener to remove
  */
  public boolean removeListener(ClientListener clientListener) {
    if (!_clientListeners.contains(clientListener)) return false;
    _clientListeners.remove(clientListener);
    return true;
  }


  /**
  * Notifies the listeners that message is received from server
  */
  public void notifyMessageReceived(short message, Object obj) {
    for (ClientListener listener: _clientListeners) {
      listener.clientMessageReceived(message, obj);
    }
  }


  private Socket server; // soket za komunikaciju sa serverom
  private User user; // klijent je vezan zza korisnika...
  public ObjectOutputStream out; // stream-ovi za pisanje i citanje.
  public ObjectInputStream in;
  private short command; // id komande koju saljemo
  private Object message;

  /* listeners of this class */
  private HashSet<ClientListener> _clientListeners = new HashSet();
}
